package com.zzl.java8.lambda6;

import org.junit.jupiter.api.Test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 参考：https://blog.csdn.net/justloveyou_/article/details/79562574
 * description: java8的stream api学习
 * @author 朱正磊
 * @date 2020-05-07 09:31:35
 */
public class StreamApiLearning {

    /**
     * 流的构造与转换---构造Stream
     */
    @Test
    void test1() {
        //1、Individual values
        Stream<String> stream = Stream.of("a", "b", "c");
        stream.forEach(System.out::print);

        System.out.println();

        //2、Arrays
        String[] strArray = {"d", "e", "f"};
        stream = Stream.of(strArray);
        stream.forEach(System.out::print);

        System.out.println();

        //3、Collections
        List<String> list = Arrays.asList(strArray);
        stream = list.stream();
        stream.forEach(System.out::print);
    }

    /**
     * IntStream的使用
     */
    @Test
    void test2() {
        // 123
        IntStream.of(1, 2, 3).forEach(System.out::print);
        System.out.println();

        // 12（前闭后开）
        IntStream.range(1, 3).forEach(System.out::print);
        System.out.println();

        // 123（前闭后闭）
        IntStream.rangeClosed(1, 3).forEach(System.out::print);
    }

    /**
     * 流也可以转换为其它数据结构
     */
    @Test
    void test3() {
        String[] strArray = {"d", "e", "f"};
        Stream<String> stream = Stream.of(strArray);

        // 1. Array
        String[] array = stream.toArray(String[]::new);
        Arrays.stream(array).forEach(System.out::print);
        System.out.println();

        // 2. Collection
        List<String> arrayList = stream.collect(Collectors.toList());
        LinkedList<String> linkedList = stream.collect(Collectors.toCollection(LinkedList::new));
        Set<String> hashSet = stream.collect(Collectors.toSet());
        LinkedHashSet<String> linkedHashSet = stream.collect(Collectors.toCollection(LinkedHashSet::new));
        Stack<String> stack = stream.collect(Collectors.toCollection(Stack::new));

        // 3. String
        String string = stream.collect(Collectors.joining());
    }

    /**
     * map/flatMap
     */
    @Test
    void test4() {
        // map
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = list.stream().map(e -> e * e).collect(Collectors.toList());
        // 1
        // 4
        // 9
        // 16
        // 25
        collect.forEach(System.out::println);

        // flatMap
        Stream<List<Integer>> listStream = Stream.of(
                Arrays.asList(1, 2),
                Arrays.asList(1, 2, 3),
                Arrays.asList(1, 3, 5, 7));
        Stream<Integer> integerStream = listStream.flatMap(Collection::stream);
        // 1
        // 2
        // 1
        // 2
        // 3
        // 1
        // 3
        // 5
        // 7
        integerStream.forEach(System.out::println);
    }

    /**
     * filter
     */
    @Test
    void test5() {
        // 留下偶数
        Integer[] numArray = {1, 2, 3, 4, 5, 6};
        Integer[] evenArray = Stream.of(numArray).filter(e -> e % 2 == 0).toArray(Integer[]::new);
        // 2
        // 4
        // 6
        Arrays.stream(evenArray).forEach(System.out::println);
    }

    /**
     * peek
     */
    @Test
    void test6() {
        List<String> collect = Stream.of("one", "two", "three", "four", "five").filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value：" + e)).map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value：" + e)).collect(Collectors.toList());
        // Filtered value：three
        // Mapped value：THREE
        // Filtered value：four
        // Mapped value：FOUR
        // Filtered value：five
        // Mapped value：FIVE
        // THREE
        // FOUR
        // FIVE
        collect.forEach(System.out::println);
    }

    /**
     * findFirst
     */
    @Test
    void test7() {
        List<String> list = Arrays.asList("a", "b", "c");
        Optional<String> optional = list.stream().findFirst();
        String s = optional.orElse("*");
        // a
        System.out.println(s);
    }

    /**
     * findAny
     */
    @Test
    void test8() {
        List<String> list = Arrays.asList("a", "b", "c");
        Optional<String> optional = list.stream().findAny();
        String s = optional.orElse("*");
        // a
        System.out.println(s);
    }

    /**
     * reduce
     */
    @Test
    void test9() {
        // 字符串连接，concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        // ABCD
        System.out.println(concat);

        // 求最小值，minValue = -3.5
        Double minValue = Stream.of(-3.5, 2.0, -1.0, 1.0).reduce(Double.MAX_VALUE, Double::min);
        // -3.5
        System.out.println(minValue);

        // 求最大值，maxValue = 2.0
        Double maxValue = Stream.of(-3.5, 2.0, -1.0, 1.0).reduce(Double.MIN_VALUE, Double::max);
        // 2.0
        System.out.println(maxValue);

        // 求和，sumValue = 10, 有起始值
        Integer sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
        // 10
        System.out.println(sumValue);

        // 求和，sumValue = 10, 无起始值
        Optional<Integer> optional = Stream.of(1, 2, 3, 4).reduce(Integer::sum);
        sumValue = optional.orElse(-1);
        // 10
        System.out.println(sumValue);

        // 过滤，字符串连接，concat = "ace"
        concat = Stream.of("a", "B", "c", "D", "e", "F")
                .filter(e -> e.compareTo("Z") > 0)
                .reduce("", String::concat);
        // ace
        System.out.println(concat);
    }

    /**
     * limit/skip
     * limit返回Stream的前面n个元素；skip则是扔掉前n个元素（它是由一个叫 subStream的方法改名而来）。
     */
    @Test
    void test10() {
        List<Person> personList = new ArrayList<>();
        Person person;
        for (int i = 1; i < 10000; i++) {
            person = new Person(10, "name" + i, "Male");
            personList.add(person);
        }
        List<String> nameList = personList.stream()
                .map(Person::getName)
                .limit(10)
                .skip(3)
                .collect(Collectors.toList());
        // name4
        // name5
        // name6
        // name7
        // name8
        // name9
        // name10
        nameList.forEach(System.out::println);
    }

    /**
     * sorted
     * 对Stream的排序通过sorted进行，
     * 它比数组的排序更强之处在于你可以首先对Stream进行各类map、filter、limit、skip甚至distinct来减少元素数量后再排序，这能帮助程序明显缩短执行时间。
     */
    @Test
    void test11() {
        List<Person> personList = new ArrayList<>();
        Person person;
        for (int i = 1; i < 6; i++) {
            person = new Person(10, "name" + i, "Male");
            personList.add(person);
        }
        List<Person> collect = personList.stream()
                .limit(2)
                .sorted(Comparator.comparing(Person::getName))
                .collect(Collectors.toList());
        // Person{age=10, name='name1', gender='Male'}
        // Person{age=10, name='name2', gender='Male'}
        collect.forEach(System.out::println);
    }

    /**
     * min/max
     */
    @Test
    void test12() {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("H:\\dms\\file\\ceshi.txt"));
            OptionalInt optional = reader.lines().mapToInt(String::length).max();
            if (optional.isPresent()) {
                int longest = optional.getAsInt();
                reader.close();
                System.out.println(longest);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * distinct
     */
    @Test
    void test13() {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("H:\\dms\\file\\ceshi.txt"));
            List<String> collect = reader.lines()
                    .flatMap(line -> Stream.of(line.split("")))
                    .filter(word -> word.length() > 0)
                    .map(String::toLowerCase)
                    .distinct()
                    .sorted()
                    .collect(Collectors.toList());
            // abcdfqrsvz
            collect.forEach(System.out::print);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Match
     * Stream有三个match方法，从语义上说：
     *　  (1).allMatch：Stream 中全部元素符合传入的 predicate，返回 true;
     *　  (2).anyMatch：Stream 中只要有一个元素符合传入的 predicate，返回 true;
     *　  (3).noneMatch：Stream 中没有一个元素符合传入的 predicate，返回 true.
     */
    @Test
    void test14() {
        List<Person> personList = Arrays.asList(
                new Person(10, "zhangsan", "Male"),
                new Person(22, "lisi", "Female"),
                new Person(34, "wangwu", "Female"),
                new Person(48, "zhuliu", "Female"),
                new Person(56, "tianqi", "Male")
        );
        boolean allMatch = personList.stream().allMatch(e -> e.getAge() > 20);
        // false
        System.out.println(allMatch);

        boolean anyMatch = personList.stream().anyMatch(e -> e.getAge() > 50);
        // true
        System.out.println(anyMatch);

        boolean noneMatch = personList.stream().noneMatch(e -> e.getAge() > 60);
        // true
        System.out.println(noneMatch);
    }

}
